using System;
using System.Collections.Generic;
using System.Text;

using Vibstudio.X4NET.IO.INI.Model.Configuration;

namespace Vibstudio.X4NET.IO.INI.Model.Formatting
{
    public class DefaultIniDataFormatter : IIniDataFormatter
    {
        IIniParserConfiguration _configuration;
        
        #region Initialization

        public DefaultIniDataFormatter():this(new DefaultIniParserConfiguration()) {}
        
        public DefaultIniDataFormatter(IIniParserConfiguration configuration)
        {
            if (configuration == null) throw new ArgumentNullException("configuration");
            Configuration = configuration;
        }
        
        #endregion
        
        public virtual string IniDataToString(IniData iniData)
        {
            var sb = new StringBuilder();

            if (Configuration.AllowKeysWithoutSection)
            {
                WriteKeyValueData(iniData.Global, sb);
            }

            foreach (SectionData section in iniData.Sections)
            {
                WriteSection(section, sb);
            }

            return sb.ToString();
        }
        
        public IIniParserConfiguration Configuration
        {
            get { return _configuration; }
            set { _configuration = value.Clone(); }
        }

        #region Helpers

        private void WriteSection(SectionData section, StringBuilder sb)
        {
            if (sb.Length > 0) sb.AppendLine();

            WriteComments(section.LeadingComments, sb);

            sb.AppendLine(string.Format("{0}{1}{2}",
                                        Configuration.SectionStartChar,
                                        section.SectionName,
                                        Configuration.SectionEndChar));

            WriteKeyValueData(section.Keys, sb);

            WriteComments(section.TrailingComments, sb);
        }

        private void WriteKeyValueData(KeyDataCollection keyDataCollection, StringBuilder sb)
        {

            foreach (KeyData keyData in keyDataCollection)
            {
                if (keyData.Comments.Count > 0) sb.AppendLine();

                WriteComments(keyData.Comments, sb);

                sb.AppendLine(string.Format("{0}{3}{1}{3}{2}",
                                            keyData.KeyName,
                                            Configuration.KeyValueAssigmentChar,
                                            keyData.Value,
                                            Configuration.AssigmentSpacer));
            }
        }

        private void WriteComments(IEnumerable<string> comments, StringBuilder sb)
        {
            foreach (string comment in comments)
            {
                sb.AppendLine(string.Format("{0}{1}", Configuration.CommentString, comment));
            }
        }

        #endregion
    }
} 